﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MMOG
{
    public class ChessPiece
    {
        public Object3d poly;
        public int x;
        public int y;
        public int type;
        public string name;

        public ChessPiece(String objectName, String bitmap, int x, int y, int type)
        {
            poly = new Object3d(objectName);
            poly.material = bitmap;
            this.x = x;
            this.y = y;
            this.type = type;
        }

        public bool inside(int x, int y)
        {
            return (x >= 0) && (y >= 0) && (x < 8) && (y < 9);
        }

        public int range(int x, int y, int x2, int y2)
        {
            return (x - x2) * (x - x2) + (y - y2) * (y - y2);
        }

        virtual public bool canMove(int toX, int toY, Chessboard3d board)
        {
            return true;
        }
    }

    public class Rook : ChessPiece
    {
        public Rook(String objectName, String bitmap, int x, int y, int type)
            : base(objectName, bitmap, x, y, type)
        {
            this.name = "Rook";
        }

        public override bool canMove(int toX, int toY, Chessboard3d board)
        {
            if ((x != toX) && (y != toY)) return false;
            for (int i = 0; i < 8; i++)
                for (int j = 0; j < 9; j++)
                    if ((Math.Abs(i - x) + Math.Abs(i - toX) == Math.Abs(toX - x))
                        && (Math.Abs(j - y) + Math.Abs(j - toY) == Math.Abs(toY - y))
                        && (range(i, j, x, y) * range(i, j, toX, toY) != 0)
                        && (board.table[i][j] != null))
                        return false;
            return true;
        }
    }

    public class Horse : ChessPiece
    {
        public Horse(String objectName, String bitmap, int x, int y, int type)
            : base(objectName, bitmap, x, y, type)
        {
            this.name = "Horse";
        }

        public override bool canMove(int toX, int toY, Chessboard3d board)
        {
            if (range(x, y, toX, toY) == 5)
                if (board.table[x + (toX - x) / 2][y + (toY - y) / 2] != null) return false;
                else return true;
            return false;
        }
    }

    public class Elephant : ChessPiece
    {
        public Elephant(String objectName, String bitmap, int x, int y, int type)
            : base(objectName, bitmap, x, y, type)
        {
            this.name = "Elephant";
        }

        public override bool canMove(int toX, int toY, Chessboard3d board)
        {
            if ((toY >= 5) && (range(x, y, toX, toY) == 8))
                if (board.table[(x + toX) / 2][(toY + y) / 2] != null) return false;
                else return true;
            return false;
        }
    }

    public class Guard : ChessPiece
    {
        public Guard(String objectName, String bitmap, int x, int y, int type)
            : base(objectName, bitmap, x, y, type)
        {
            this.name = "Guard";
        }

        public override bool canMove(int toX, int toY, Chessboard3d board)
        {
            if ((range(toX, toY, 4, 8) <= 2) && (range(x, y, toX, toY) == 2))
                return true;
            return false;
        }
    }

    public class General : ChessPiece
    {
        public General(String objectName, String bitmap, int x, int y, int type)
            : base(objectName, bitmap, x, y, type)
        {
            this.name = "General";
        }

        public override bool canMove(int toX, int toY, Chessboard3d board)
        {
            if ((range(toX, toY, 4, 8) <= 2) && (range(x, y, toX, toY) == 1))
                return true;
            return false;
        }
    }

    public class Soldier : ChessPiece
    {
        public Soldier(String objectName, String bitmap, int x, int y, int type)
            : base(objectName, bitmap, x, y, type)
        {
            this.name = "Soldier";
        }

        public override bool canMove(int toX, int toY, Chessboard3d board)
        {
            if (range(x, y, toX, toY) == 1)
                if ((y - toY == 1) || ((y <= 4) && (toY <= y))) return true;
            return false;
        }
    }

    public class Chessboard3d
    {
        public int WIDTH = 9;
        public int HEIGHT = 10;

        OpenGLControl glControl;
        public ChessPiece[][] table;
        public Object3d board;
        public Object3d selector;

        public float xzAngle = 0;
        public float yzAngle = 0;
        public float range = 0;

        float startX = -1.19700f;
        float startY = -1.50800f;
        float rangeX = 0.30075f;
        float rangeY = 0.33530f;

        int selectX = 0;
        int selectY = 9;

        int selectedX = -1;
        int selectedY = -1;

        float selectColor = 0.2f;
        float selectedColor = 0f;
        float selectAcc = 0.01f;

        public void resetBoard()
        {
            for (int i = 0; i < WIDTH; i++)
                for (int j = 0; j < HEIGHT; j++)
                    table[i][j] = null;

            table[0][6] = new Soldier("piece.obj", "blacksoldier.bmp", 0, 6, 0);
            table[2][6] = new Soldier("piece.obj", "blacksoldier.bmp", 2, 6, 0);
            table[4][6] = new Soldier("piece.obj", "blacksoldier.bmp", 4, 6, 0);
            table[6][6] = new Soldier("piece.obj", "blacksoldier.bmp", 6, 6, 0);
            table[8][6] = new Soldier("piece.obj", "blacksoldier.bmp", 8, 6, 0);

            table[4][9] = new General("piece.obj", "blackgeneral.bmp", 4, 9, 0);

            table[0][9] = new Rook("piece.obj", "blackrook.bmp", 0, 9, 0);
            table[8][9] = new Rook("piece.obj", "blackrook.bmp", 8, 9, 0);

            table[1][9] = new Horse("piece.obj", "blackhorse.bmp", 1, 9, 0);
            table[7][9] = new Horse("piece.obj", "blackhorse.bmp", 7, 9, 0);

            table[2][9] = new Elephant("piece.obj", "blackelephant.bmp", 2, 9, 0);
            table[6][9] = new Elephant("piece.obj", "blackelephant.bmp", 6, 9, 0);

            table[3][9] = new Guard("piece.obj", "blackguard.bmp", 3, 9, 0);
            table[5][9] = new Guard("piece.obj", "blackguard.bmp", 5, 9, 0);

            table[1][7] = new ChessPiece("piece.obj", "blackcannon.bmp", 1, 7, 0);
            table[7][7] = new ChessPiece("piece.obj", "blackcannon.bmp", 7, 7, 0);


            table[0][3] = new Soldier("piece.obj", "redsoldier.bmp", 0, 6, 1);
            table[2][3] = new Soldier("piece.obj", "redsoldier.bmp", 2, 6, 1);
            table[4][3] = new Soldier("piece.obj", "redsoldier.bmp", 4, 6, 1);
            table[6][3] = new Soldier("piece.obj", "redsoldier.bmp", 6, 6, 1);
            table[8][3] = new Soldier("piece.obj", "redsoldier.bmp", 8, 6, 1);

            table[4][0] = new General("piece.obj", "redgeneral.bmp", 4, 9, 1);

            table[0][0] = new Rook("piece.obj", "redrook.bmp", 0, 9, 1);
            table[8][0] = new Rook("piece.obj", "redrook.bmp", 8, 9, 1);

            table[1][0] = new Horse("piece.obj", "redhorse.bmp", 1, 9, 1);
            table[7][0] = new Horse("piece.obj", "redhorse.bmp", 7, 9, 1);

            table[2][0] = new Elephant("piece.obj", "redelephant.bmp", 2, 9, 1);
            table[6][0] = new Elephant("piece.obj", "redelephant.bmp", 6, 9, 1);

            table[3][0] = new Guard("piece.obj", "redguard.bmp", 3, 9, 1);
            table[5][0] = new Guard("piece.obj", "redguard.bmp", 5, 9, 1);

            table[1][2] = new ChessPiece("piece.obj", "redcannon.bmp", 1, 7, 1);
            table[7][2] = new ChessPiece("piece.obj", "redcannon.bmp", 7, 7, 1);
        }

        public Chessboard3d(OpenGLControl glControl)
        {
            this.glControl = glControl;

            table = new ChessPiece[WIDTH][];
            for (int i = 0; i < WIDTH; i++) table[i] = new ChessPiece[HEIGHT];
            board = new Object3d("chessboard.obj");
            selector = new Object3d("selector.obj");
            resetBoard();

            OpenGLControl.glMatrixMode(OpenGLControl.GL_MODELVIEW);
            OpenGLControl.glLoadIdentity();
            OpenGLControl.glTranslatef(0.0f, 0f, -3.0f);

            range = 2f;
            xzAngle = 0;
            yzAngle = 70;
            setView();
        }

        public void setView()
        {
            float xza = (float)(xzAngle * Math.PI / 180);
            float yza = (float)(yzAngle * Math.PI / 180);
            float eX = (float)(Math.Sin(xza) * Math.Cos(yza) * range);
            float eY = (float)(Math.Sin(yza) * range);
            float eZ = (float)(Math.Cos(xza) * Math.Cos(yza) * range);
            OpenGLControl.gluLookAt(eX, eY, eZ, 0, 0, 0, 0, 1, -0.1);
        }

        public int getX(int x)
        {
            return 0;
        }

        public void drawSelector()
        {
            OpenGLControl.glPushMatrix();
            OpenGLControl.glTranslatef(startX + rangeX * selectX, 0.01f, startY + rangeY * selectY);
            if ((selectColor > 0.3f) || (selectColor < 0.01f))
            {
                selectAcc = -selectAcc;
            }
            selectColor += selectAcc;
            glControl.drawObjectColor(selector, 1f, 0.5f, 0.25f, 0.5f + selectColor, 0.7f + selectColor);
            OpenGLControl.glPopMatrix();

            if (selectedX >= 0)
            {
                OpenGLControl.glPushMatrix();
                OpenGLControl.glTranslatef(startX + rangeX * selectedX, 0.01f, startY + rangeY * selectedY);
                OpenGLControl.glRotatef(selectedColor, 0f, 1.0f, 0.0f);
                if (selectedColor > 180f)
                    selectedColor = 0f;
                selectedColor += 5;
                glControl.drawObjectColor(selector, 0f, 0.5f, 1f, 0.7f, 0.9f);
                OpenGLControl.glPopMatrix();
            }
        }

        public void moveLeft()
        {
            if (selectX > 0) selectX--;
        }

        public void moveRight()
        {
            if (selectX < WIDTH - 1) selectX++;
        }

        public void moveUp()
        {
            if (selectY > 0) selectY--;
        }

        public void moveDown()
        {
            if (selectY < HEIGHT - 1) selectY++;
        }

        public void select()
        {
            if (selectedX < 0)
            {
                if ((table[selectX][selectY] != null) && (table[selectX][selectY].type == 0))
                {
                    selectedX = selectX;
                    selectedY = selectY;
                }
            }
            else
            {
                if ((selectX == selectedX) && (selectY == selectedY))
                {
                    selectedX = -1;
                    selectedY = -1;
                }
                else if ((table[selectX][selectY] == null) || (table[selectX][selectY].type == 1))
                {
                    if (table[selectedX][selectedY].canMove(selectX, selectY, this))
                    {
                        table[selectX][selectY] = table[selectedX][selectedY];
                        table[selectedX][selectedY] = null;
                        table[selectX][selectY].x = selectX;
                        table[selectX][selectY].y = selectY;
                        selectedX = -1;
                        selectedY = -1;
                    }
                }
            }
        }

        public void draw()
        {
            OpenGLControl.glMatrixMode(OpenGLControl.GL_MODELVIEW);
            OpenGLControl.glLoadIdentity();
            OpenGLControl.glTranslatef(0.0f, 0f, -3.0f);
            setView();
            OpenGLControl.glPushMatrix();
            OpenGLControl.glClear(OpenGLControl.AttribMask.GL_COLOR_BUFFER_BIT | OpenGLControl.AttribMask.GL_DEPTH_BUFFER_BIT);
            glControl.drawObject(board, 1f);
            OpenGLControl.glPopMatrix();
            drawSelector();

            for (int i = 0; i < WIDTH; i++)
                for (int j = 0; j < HEIGHT; j++)
                    if (table[i][j] != null)
                    {
                        OpenGLControl.glPushMatrix();
                        OpenGLControl.glTranslatef(startX + rangeX * i, 0, startY + rangeY * j);
                        OpenGLControl.glRotatef(180, 0f, 1.0f, 0.0f);
                        glControl.drawObject(table[i][j].poly, 1f);
                        OpenGLControl.glPopMatrix();
                    }
            OpenGLControl.glFlush();
            glControl.SwapBuffer();
        }
    }
}
